package com.sghd.fight.module.game.service.match;

import com.sghd.fight.module.game.event.PushEvent;
import com.sghd.fight.module.game.service.GameService;
import com.sghd.fight.module.game.service.configure.Configure;
import com.sghd.fight.module.game.service.room.IRoom;
import com.sghd.fight.module.game.service.work.RoomRunner;
import com.sghd.fight.module.game.service.work.RoomWork;
import com.sghd.fight.net.SocketEnum;
import com.sghd.pojo.fight.game.PlayerVo;
import com.sghd.pojo.fight.game.Result;
import com.sghd.pojo.fight.game.RoomType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * @author frank
 * @date 2018-10-25 10:22
 * @desc
 **/
public abstract class AbstractMathcer implements Matcher {

    protected Logger logger = LoggerFactory.getLogger(getClass());

    protected RoomType type;
    protected GameService gameService;
    protected Configure configure;
    /** 匹配队列*/
    protected Map<Long, PlayerVo> matchers = new HashMap<>();
    /** 每个房间人数*/
    protected int roomCount;
    /** 匹配心跳间隔*/
    private int idea;
    /**
     * 执行匹配逻辑
     * @param now
     * @return
     */
    public abstract List<IRoom> doMatch(Date now);

    public AbstractMathcer(GameService battleService, Configure configure, int idea) {
        this.idea = idea;
        this.gameService = battleService;
        this.configure = configure;
        this.type = configure.getType();
        roomCount = configure.getConfigService().getRoomConfig(type).getPlayerCount();
    }

    @Override
    public void timer(Date now) {
        gameService.addTimer(new RoomWork(new RoomRunner() {
            @Override
            public void run(Date now) {
                match(now);
            }
        }, new Date(now.getTime() + idea), RoomWork.MATCH));
    }

    @Override
    public void match(Date now) {
        List<IRoom> rooms = doMatch(now);
        if (null != rooms && !rooms.isEmpty()) {
            gameService.matched(rooms);
        }
        timer(now);
    }

    @Override
    public void add(PlayerVo playerInfo) {
        if (matchers.containsKey(playerInfo.getPlayerId())) {
            logger.error("[{}]重复进入房间！", playerInfo.getPlayerId());
            return;
        }
        matchers.put(playerInfo.getPlayerId(), playerInfo);
    }

    @Override
    public RoomType getType() {
        return type;
    }

    @Override
    public void quit(long playerId) {
        PlayerVo prev = matchers.remove(playerId);
        if (prev != null) {
            logger.debug("玩家[{}]取消匹配！", playerId);
            gameService.post(PushEvent.NAME, PushEvent.valueOf(Result.valueOf(playerId), playerId, SocketEnum.CANCEL_MATCH));
            prev = null;
        }
    }

    @Override
    public boolean containsKey(long playerId) {
        return matchers.containsKey(playerId);
    }

    @Override
    public int size() {
        return matchers.size();
    }

    @Override
    public void kick() {
        for (PlayerVo info : matchers.values()) {
            quit(info.getPlayerId());
        }
    }

    protected PlayerVo matched(int index, Set<PlayerVo> outed) {
        for (PlayerVo playerInfo : matchers.values()) {
            //该目标已经匹配给另一个房间
            if (outed.contains(playerInfo)) {
                continue;
            }
            playerInfo.setIndex(index);
            outed.add(playerInfo);
            return playerInfo;
        }
        throw new RuntimeException("匹配玩家发生未知错误！");
    }

    protected Long getRoomId() {
        List<Long> roomIds = new ArrayList<>(gameService.getRooms().keySet());
        Collections.sort(roomIds);
        if (roomIds.isEmpty()) {
            return 1L;
        }
        for (int i = 0; i < roomIds.size(); i++) {
            Long roomId = roomIds.get(i);
            int nextIdx = i + 1;
            if (nextIdx >= roomIds.size()) {
                return roomId + 1;
            }
            Long nextRoomId = roomIds.get(nextIdx);
            if (nextRoomId - 1 > roomId) {
                return roomId + 1;
            }
        }
        throw new RuntimeException("生成房间id出错！");
    }
}
